﻿/********************************************************************************/
/* 	state.d																		*/
/*------------------------------------------------------------------------------*/
/*	製作		（　゜ワ゜）ノ　／　松久貫太									*/
/*	製作開始　	2007/05/11														*/
/*	MAIL		omega@personal.email.ne.jp										*/
/*	URL		http://nagoya.cool.ne.jp/o_mega										*/
/*																				*/
/*	このソースは「やわらかライセンス」の元で配布されています。					*/
/*-更新履歴---------------------------------------------------------------------*/
/*	2007/--/--																	*/
/*-その他-----------------------------------------------------------------------*/
/*	なし																		*/
/********************************************************************************/

/* ライブラリのインポート *******************************************************/
private import hell2;		// dHell2ライブラリ
private import screen;
private import player;
private import shot;
private import enemy;
private import vector;
private import effect;
private import keypad;
private import actor;
private import stage;
private import clickable;

private import std.string;
private import std.math;
private import std.math2;
private import std.stream;
private import std.thread;

private import defines;

/* グローバル定数定義 ***********************************************************/
GameState g_gamestate = null;


/* load *************************************************************************/
/*	リソースの読み込み															*/
/*-引数-------------------------------------------------------------------------*/
/*	なし																		*/
/*-返り値-----------------------------------------------------------------------*/
/*	なし																		*/
/********************************************************************************/
void load()
{
	Hell_loadTexture("font","resource/font/font.bmp" , [255,255,255]);
	Hell_loadWAV("fire" , "resource/sound/explosion1.wav");
	Hell_loadWAV("destroy" , "resource/sound/bang.wav");
	Hell_loadWAV("reload" , "resource/sound/kacha1.wav");
	Hell_loadWAV("click" , "resource/sound/click1.wav");
	
	Hell_write("resource loaded.\n");
}

/* GameState ********************************************************************/
/*	ゲーム全体の状態遷移を管理するクラス										*/
/********************************************************************************/
class GameState
{
private:
	int msg;				// リクエストメッセージ
public:
	enum
	{
		MSG_NONE,
		MSG_REQ_TITLE,			// タイトル状態へ　行きたい
		MSG_REQ_GAME,			// ゲーム
	}
	
	void move(){}
	void draw(){}
	
	// 設定
	void setMsg(int m)
	{
		msg = m;
	}
	// 取得
	int getMsg()
	{
		return msg;
	}
}



void loop()
{
	if(g_gamestate)
	{
		// メッセージ指示による状態遷移
		switch(g_gamestate.msg)
		{
			case GameState.MSG_NONE:
				break;
			case GameState.MSG_REQ_TITLE:
				g_gamestate = new TitleMain();
				break;
			case GameState.MSG_REQ_GAME:
				g_gamestate = new GameMain();
				break;
			default:
				Hell_write("Uknown msg at loop.");
		}
	}
	else
	{
		// 初期状態
		g_gamestate = new TitleMain();//new GameMain();
		Hell_write("Exec loop.\n");
	}
	
	g_gamestate.move();
	g_gamestate.draw();
}

/* TitleMain ********************************************************************/
/*	タイトルの状態																*/
/********************************************************************************/
enum REPLAY_TYPE{
	LAST,
	RAND,
}
static int g_replay_cnt = 5;
static int g_rep_type = REPLAY_TYPE.RAND;

class TitleMain : GameState
{
public:
	int timer;
	Vec3 mouse;
	ClickablePool menu;
	
	this()
	{
		timer = 0;
		mouse = new Vec3();
		
		Hell_playBgm("resource/sound/supertanktime01.ogg", 3000);
		
		menu = new ClickablePool();
		menu.add("[-]" , new Vec3(260 , 360 , 0) , new Vec3(48 , 32 , 0));
		menu.add("[+]" , new Vec3(330 , 360 , 0) , new Vec3(48 , 32 , 0));
		menu.add("START" , new Vec3(280 , 400 , 0) , new Vec3(96 , 32 , 0));
		menu.add("MODE" , new Vec3(285 , 300 , 0) , new Vec3(96 , 32 , 0));
	}
	
	void move()
	{
		timer++;
		
		mouse.x = (Hell_getMouseX() - 320) / 320.0 * CHAR_X_ABSMAX;
		mouse.y = (Hell_getMouseY() - 240) / 240.0 * CHAR_Y_ABSMAX;
		
		string select = menu.getMouseClick();
		
		if(select == "START"){
			setMsg(GameState.MSG_REQ_GAME);
			Hell_playWAV("destroy");
		}else if(select == "[-]"){
			Hell_playWAV("click");
			if(g_replay_cnt > 0) 	g_replay_cnt--;
		}else if(select == "[+]"){
			Hell_playWAV("click");
			if(g_replay_cnt < 15) g_replay_cnt++;
		}else if(select == "MODE"){
			Hell_playWAV("click");
			if(g_rep_type == REPLAY_TYPE.RAND){
				g_rep_type = REPLAY_TYPE.LAST;
			}else{
				g_rep_type = REPLAY_TYPE.RAND;
			}
		}
	}
	
	void draw()
	{
		Hell_begin();
		resetPerspective();
		Hell_setAlpha(HELL_ALPHA_PRODUCT);
		Hell_drawRect(0,0,640,480, 0, 0, 128,160,240,255);
		
		Hell_setAlpha(HELL_ALPHA_NORMAL);
		/*
		glTranslatef(0 , 0 , CHAR_Z_SURFACE);
		glRotatef(mouse.y / CHAR_Y_ABSMAX * 10 , -mouse.x / CHAR_X_ABSMAX * 10 , 0);
		glTranslatef(0 , 0 , -CHAR_Z_SURFACE);
		*/
		resetPerspective();
		
		menu.draw();
		
		Hell_drawFont("RE-PLAYERS : " ~ std.string.toString(g_replay_cnt) , 200, 340 , 2 , 255,255,255);
		
		Hell_drawFont("SUPER TANK TIME" , 80, 160 , 4 , 255,255,255);
		Hell_drawFont("OMEGA WITH GAMEHELL2000" , 140, 480-48 , 2 , 160,160,160);
		
		if(g_rep_type == REPLAY_TYPE.RAND){
			Hell_drawFont("RANDOM RE-PLAYERS" , 180, 280 , 2 , 255,255,255);
		}else{
			Hell_drawFont(" LAST RE-PLAYERS " , 180, 280 , 2 , 255,255,255);
		}
		
		setPerspective();
		glLoadIdentity();
			glTranslatef(mouse.x , mouse.y , CHAR_Z_SURFACE);
			glRotatef(timer * 1.5 , timer * 1.1 , timer * 1.7);
			glColor4f(1,1,1,1);
			TriangleShape.drawWire();
			
			glRotatef(timer * 1.5 , timer * 1.1 , timer * 1.7);
			glColor4f(1,1,1,0.8);
			glScalef(2,2,2);
			TriangleShape.drawWire();
	}
}

/* GameMain *********************************************************************/
/*	ゲーム本体の状態															*/
/********************************************************************************/

//MouseRecorder[] g_mouserecorders = null;

class GameMain : GameState
{
public:
	PlayerActor playeractor = null;
	ShotActor shotactor = null;
	EnemyActor enemyactor = null;
	//EShotActor eshotactor = null;
	EffectActor effectactor = null;
	PerticleActor perticleactor = null;
	Stage stage = null;
	
	MouseRecorder player_mr = null;
	
	int timer;
	int over_timer;
	
	int blur_r , blur_g , blur_b;
	int nblur_r , nblur_g , nblur_b;
	
	int score ;
	
 	Vec3 cursor;
	
	
	this()
	{
		stage = new TestStage(this);
		
		Hell_playBgm("resource/sound/dktrance02.ogg", 3000);
		
		playeractor = new PlayerActor(this,16);
		shotactor = new ShotActor(this,64);
		enemyactor = new EnemyActor(this,256);
		//eshotactor = new EShotActor(this,128);
		effectactor = new EffectActor(384);
		perticleactor = new PerticleActor(4096);
		timer = 0;
		score = 0;
		over_timer = 0;
		
		cursor = new Vec3();
		player_mr = new MouseRecorder();
		playeractor.add(new PlayerSpec(PlayerSpec.PLAYER , player_mr));
		playeractor.add(new PlayerSpec(PlayerSpec.BASE , null));
		
		loadReplayers();
		
		blur_r = 128;
		blur_g = 160;
		blur_b = 240;
				nblur_g = 128;
				nblur_r = 128;
				nblur_b = 128;
	}
	
	void move()
	{
		cursor.x = (Hell_getMouseX() - 320) / 320.0 * CHAR_X_ABSMAX;
		cursor.y = (Hell_getMouseY() - 240) / 240.0 * CHAR_Y_ABSMAX;
		if(!stage.isFinish())
		{
			timer++;
			playeractor.move();
			playeractor.separate();
			
			if(timer % 180 == 0){
				nblur_g = Hell_randInt(128,224);
				nblur_r = Hell_randInt(128,224);
				nblur_b = Hell_randInt(128,224);
			}
			if(timer % 5 == 0){
				blur_g = (blur_g * 15 + nblur_g) / 16;
				blur_r = (blur_r * 15 + nblur_r) / 16;
				blur_b = (blur_b * 15 + nblur_b) / 16;
			}
			
			
			stage.update();
		}
		else
		{
			if(over_timer == 0) Hell_playBgm("resource/sound/10.ogg", 3000);
			over_timer++;
			if(Hell_isPushMouse() & 0x01 && over_timer > 30)
			{
				saveReplay();
				setMsg(GameState.MSG_REQ_TITLE);
			}
			
			enemyactor.destroyAll();
		}
		
		shotactor.move();
		effectactor.move();
		perticleactor.move();
		enemyactor.move();
		//eshotactor.move();
	}
	
	void draw()
	{
		/*
		if(ref){
			Hell_setAlpha(HELL_ALPHA_REVERSE);
			Hell_drawRect(0,0,640,480, 0, 0, 255,255,255,255);
		}*/
		
		//Hell_begin();
		resetPerspective();
		Hell_setAlpha(HELL_ALPHA_PRODUCT);
		//Hell_drawRect(0,0,640,480, 0, 0, 128,160,240,255);
		//Hell_drawRect(0,0,640,480, 0, 0, 240,160,128,255);
		Hell_drawRect(0,0,640,480, 0, 0, blur_r,blur_g,blur_b,255);
		
		Hell_setAlpha(HELL_ALPHA_NORMAL);
		setPerspective();
		
		// 視点ぐりぐり
		glLoadIdentity();
		//glTranslatef(cursor.x , cursor.y , CHAR_Z_SURFACE);
		//glRotatef(cursor.y / CHAR_Y_ABSMAX * 3, -cursor.x / CHAR_X_ABSMAX * 3, 0);
		//glTranslatef(-cursor.x , -cursor.y , -CHAR_Z_SURFACE);
		
		// 床グリッド
		for(double x= -CHAR_X_ABSMAX ; x <= CHAR_X_ABSMAX ; x += 5.0)
			{
			for(double y = -CHAR_Y_ABSMAX ; y <= CHAR_Y_ABSMAX ; y += 5.0)
			{
				glPushMatrix();
				glTranslatef(x,y,CHAR_Z_SURFACE);
				glScalef(0.5 , 0.5 , 0);
				glColor4f(0.2,0.2,0.2, 1);
				LineShape.drawWireThin(new Vec3(-1,0,0) , new Vec3(1,0,0));
				LineShape.drawWireThin(new Vec3(0,-1,0) , new Vec3(0,1,0));
				glPopMatrix();
			}
		}
		
		enemyactor.draw();
		//eshotactor.draw();
		shotactor.draw();
		enemyactor.drawHigh();
		
		playeractor.drawPlayer();
		
		Hell_setAlpha(HELL_ALPHA_ADD);
		resetCullFace();
		effectactor.draw();
		perticleactor.draw();
		Hell_setAlpha(HELL_ALPHA_NORMAL);
		
		stage.draw();
		
		resetPerspective();
		playeractor.drawStatus();
		
	//	Hell_drawFont("TIMER:" ~ std.string.toString(cast(double)(timer / 6) / 10) ,0 ,0 , 2);
	//	Hell_drawFont("SHOT:" ~ std.string.toString(shotactor.countExist()) ,0 ,16 , 2);
	//	Hell_drawFont("ENEM:" ~ std.string.toString(enemyactor.countExist()) ,0 ,32 , 2);
	//	Hell_drawFont("EFCT:" ~ std.string.toString(effectactor.countExist()) ,0 ,48 , 2);
	//	Hell_drawFont("PRTC:" ~ std.string.toString(perticleactor.countExist()) ,0 ,64 , 2);
	//	Hell_drawFont("SCORE:" ~ std.string.toString(score) ,0 ,32 , 2);
		
		int tm = stage.getTotalFrame() - timer;
		if(tm < 0) tm = 0;
		if(tm < 60 * 5){
			Hell_drawFont("TIMER:" ~ std.string.toString(tm / 60) ,0 , 32 , 3 , 255,128,32);
		}else{
			Hell_drawFont("TIMER:" ~ std.string.toString(tm / 60) ,0 , 32 , 2);
		}
		
		if(over_timer > 60){
		/*
			float sz = over_timer * 4 + (timer % 2) * 32;
			if(sz > 640) sz = 640;
			Hell_drawCircle(320 , 460 , sz , 0 , 255,255,255);
			
			if(sz == 640)
		*/
				Hell_drawFont("G A M E  O W A T A" ,100 , 240 , 3 , 255,128,0);
		}
		
		Hell_drawFPS();
	}
	
	void addEffect(Vec3 p ,Vec3 v,EFFECTTYPE type){
		if(type == EFFECTTYPE.POINT){
			perticleactor.add(p,v,type);
		}else{
			effectactor.add(p,v,type);
		}
	}
	
	import std.string;
	import std.date;
	
	void saveReplay(){
		d_time tm = UTCtoLocalTime(getUTCtime());
//		Hell_write(tm == getUTCtime());
		string filename = format(
			"%04d%02d%02d%02d%02d%02d" ~ REPLAY_EXT , 
			YearFromTime(tm) , MonthFromTime(tm) , DateFromTime(tm) ,
			HourFromTime(tm) , MinFromTime(tm) , SecFromTime(tm));
			
		player_mr.save(REPLAY_PATH ~ filename);
	
	}
	
	void loadReplayers(){
		string[] fn = getReplayFiles();
		
		int[] listbuf = new int[fn.length];
		foreach(inout a ; listbuf) a = -1;
		
		if(g_rep_type == REPLAY_TYPE.RAND){
			// シャッフル
			for(int t=0 ; (t<listbuf.length && t<g_replay_cnt) ; t++){
				int r;
				for(;;){
					r = (std.random.rand() / 13) % listbuf.length;
					
					bool f = true;
					foreach(i;listbuf) if(i == r) f = false;
					
//			Hell_write(std.string.toString(r) ~ "\n");
					if(f) break;
				}
				listbuf[t] = r;
				
//			Hell_write("  " ~ std.string.toString(r) ~ "\n");
			}
		}else{
			for(int t=0 ; t<fn.length ; t++) listbuf[t] = fn.length - t - 1;
		}
		
		for(int t=0 ; (t<g_replay_cnt && t<listbuf.length ) ; t++){
			MouseRecorder mr = new MouseRecorder();
		//	Hell_write(std.string.toString(listbuf[t]) ~ "\n");
			mr.load(fn[listbuf[t]]);
			playeractor.add(new PlayerSpec(PlayerSpec.REPLAYER , mr));
			mr.setMode(MouseRecorder.REPLAY);
		}
	}
	
	string[] getReplayFiles(){
		return std.file.listdir(REPLAY_PATH , REPLAY_PATTERN);
	}
}
